package uy.org.softtech.cssuite.web.reportes;

import static org.apache.commons.lang.StringUtils.trimToEmpty;
import static org.apache.commons.lang.StringUtils.startsWithIgnoreCase;
import static uy.org.softtech.cssuite.helpers.HelperFechaHora.fechaLarga;

import java.awt.Dimension;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.Source;
import net.minidev.json.JSONArray;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.ImageUtils;
import org.apache.poi.util.IOUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.view.document.AbstractExcelView;

public class ReporteExcel extends AbstractExcelView {
	
	private Logger log = Logger.getLogger(getClass());
	
	public static final double PIXELES_POR_MILIMETROS 	= 3.78;		// MB
	public static final double PUNTOS_POR_MILIMETROS	= 2.83;     // MB
	
	@Override
	@SuppressWarnings("unchecked")
	protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
		try {
			//Extraigo datos del modelo
			String titulo = (String) model.get("REPORTE_TITULO");
			String nombreHoja = (String) model.get("REPORTE_NOMBRE_HOJA");
			String mensaje = (String) model.get("REPORTE_MENSAJE");
			JSONArray cabezales = (JSONArray) model.get("REPORTE_CABEZALES");
			JSONArray celdas = (JSONArray) model.get("REPORTE_CELDAS");
			
			//Creo una paleta de colores customizada
			HSSFPalette palette = workbook.getCustomPalette();
			palette.setColorAtIndex(HSSFColor.GREY_25_PERCENT.index, (byte) 238, (byte) 238, (byte) 238);	//#EEEEEE
			palette.setColorAtIndex(HSSFColor.GREY_40_PERCENT.index, (byte) 204, (byte) 204, (byte) 204);	//#CCCCCC
			palette.setColorAtIndex(HSSFColor.GREY_50_PERCENT.index, (byte) 85, (byte) 85, (byte) 85);		//#555555
			palette.setColorAtIndex(HSSFColor.GREY_80_PERCENT.index, (byte) 34, (byte) 34, (byte) 34);		//#222222
			
			//Genero los estilos (bordes, letras, colores, etc.)
			HSSFFont fuentesCabezales = workbook.createFont();
			fuentesCabezales.setBoldweight(Font.BOLDWEIGHT_NORMAL);
			fuentesCabezales.setColor(IndexedColors.GREY_80_PERCENT.getIndex());
						
			HSSFFont fuentesCeldas = workbook.createFont();
			fuentesCeldas.setBoldweight(Font.BOLDWEIGHT_NORMAL);
			fuentesCeldas.setColor(IndexedColors.GREY_50_PERCENT.getIndex());
			
			HSSFCellStyle estiloCabezales = workbook.createCellStyle();
			estiloCabezales.setBorderRight(CellStyle.BORDER_THIN);
			estiloCabezales.setBorderBottom(CellStyle.BORDER_THIN);
			estiloCabezales.setBorderLeft(CellStyle.BORDER_THIN);
			estiloCabezales.setBorderTop(CellStyle.BORDER_THIN);
			estiloCabezales.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCabezales.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCabezales.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCabezales.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCabezales.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
			estiloCabezales.setAlignment(CellStyle.ALIGN_CENTER);
			estiloCabezales.setFillPattern(CellStyle.SOLID_FOREGROUND);
			estiloCabezales.setFont(fuentesCabezales);
			
			HSSFCellStyle estiloCeldas = workbook.createCellStyle();
			estiloCeldas.setBorderRight(CellStyle.BORDER_THIN);
			estiloCeldas.setBorderBottom(CellStyle.BORDER_THIN);
			estiloCeldas.setBorderLeft(CellStyle.BORDER_THIN);
			estiloCeldas.setBorderTop(CellStyle.BORDER_THIN);
			estiloCeldas.setTopBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCeldas.setRightBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCeldas.setBottomBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCeldas.setLeftBorderColor(IndexedColors.GREY_40_PERCENT.getIndex());
			estiloCeldas.setFillForegroundColor(IndexedColors.WHITE.getIndex());
			estiloCeldas.setAlignment(CellStyle.ALIGN_CENTER);
			estiloCeldas.setFillPattern(CellStyle.SOLID_FOREGROUND);
			estiloCeldas.setFont(fuentesCabezales);
			
			HSSFCellStyle estiloTitulo = workbook.createCellStyle();
			estiloTitulo.setAlignment(CellStyle.ALIGN_CENTER);
			estiloTitulo.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
			
			HSSFSheet planillaElectronica = workbook.createSheet(nombreHoja);
			planillaElectronica.setAutobreaks(true);
			planillaElectronica.setDefaultColumnWidth(12);
			planillaElectronica.setDisplayFormulas(false);
			planillaElectronica.setDisplayGridlines(false);
			planillaElectronica.setDisplayZeros(false);
			planillaElectronica.setFitToPage(true);
			planillaElectronica.setHorizontallyCenter(true);
			planillaElectronica.getPrintSetup().setLandscape(true);
			planillaElectronica.getPrintSetup().setFitHeight((short)1);
			planillaElectronica.getPrintSetup().setFitWidth((short)1);
			
	        HSSFPatriarch patriarch = planillaElectronica.createDrawingPatriarch();
	        
	        int columnas = cabezales.size() - 1;	//Para excluir la última columna que tiene los links
			
			int fila = 1;
			int columna = 1;
			
			HSSFPicture imagenLogoAplicacion = null;
			HSSFPicture imagenLogoEmpresa = null;
			Dimension dimensiones = null;
			
			HSSFRow filaLogos = planillaElectronica.createRow(1);
			filaLogos.setHeightInPoints((float) ((120 / PIXELES_POR_MILIMETROS) * PUNTOS_POR_MILIMETROS));
			
			//Obtengo imágenes de logos
			WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
			String logoAplicacion = context.getResource("classpath:/uy/org/softtech/cssuite/web/recursos/img/cssuite/cssuite.png").getFile().getCanonicalPath();
			FileInputStream input = new FileInputStream(logoAplicacion);
			if (input != null) {
				byte[] bytes = IOUtils.toByteArray(input);
				input.close();
				
				dimensiones = ImageUtils.getImageDimension(new ByteArrayInputStream(bytes), Workbook.PICTURE_TYPE_PNG);
				int idx = workbook.addPicture(bytes, HSSFWorkbook.PICTURE_TYPE_PNG);
				HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) columna, fila, (short)(columna + 1), fila);
				anchor.setAnchorType(0);				
				imagenLogoAplicacion = patriarch.createPicture(anchor, idx);
				imagenLogoAplicacion.getImageDimension().setSize(dimensiones.getWidth(), dimensiones.getHeight());
			}
			
			columna = columnas - 1;
			String logoEmpresa = context.getResource("classpath:/uy/org/softtech/cssuite/web/recursos/img/cssuite/softtech.png").getFile().getCanonicalPath();
			input = new FileInputStream(logoEmpresa);
			if (input != null) {
				byte[] bytes = IOUtils.toByteArray(input);
				input.close();
				
				dimensiones = ImageUtils.getImageDimension(new ByteArrayInputStream(bytes), Workbook.PICTURE_TYPE_PNG);
				int idx = workbook.addPicture(bytes, HSSFWorkbook.PICTURE_TYPE_PNG);
				HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) columna, fila, (short)(columna + 1), fila);
				anchor.setAnchorType(0);				
				imagenLogoEmpresa = patriarch.createPicture(anchor, idx);
				imagenLogoEmpresa.getImageDimension().setSize(dimensiones.getWidth(), dimensiones.getHeight());
			}
						
			//Titulo del reporte
			fila++;
			columna = 1;
			HSSFCell celda = getCell(planillaElectronica, fila, columna);
			celda.setCellStyle(estiloTitulo);
			setText(celda, titulo);
			
			//Fecha del reporte
			columna = columnas - 2;
			celda = getCell(planillaElectronica, fila, columna);
			celda.setCellStyle(estiloTitulo);
			setText(celda, fechaLarga());
			
			//Cabezales
			fila = planillaElectronica.getLastRowNum() + 2;
			columna = 1;
			for(int idx = 0; idx < columnas; idx++) {
				String texto = (String) cabezales.get(idx);
				celda = getCell(planillaElectronica, fila, columna);
				celda.setCellStyle(estiloCabezales);
				setText(celda, texto);
				columna++;
			}
			
			//Congelamos la sección de logos, título y cabezales
			fila++;
			planillaElectronica.createFreezePane(0, fila, 0, fila);
			
			//Datos
			columna = 0;
			for(int idx = 0; idx < celdas.size(); idx++) {
				List<String> datos = (List<String>) celdas.get(idx);
				for(; columna < columnas; columna++) {
					String texto = trimToEmpty(datos.get(columna));					
					if(startsWithIgnoreCase(texto, "<span")) {		//Código HTML
						Source source = new Source(new StringReader(texto));
						Element element = source.getFirstElement();
						texto = element.getAttributeValue("title");
					}
					celda = getCell(planillaElectronica, fila, columna + 1);
					celda.setCellStyle(estiloCeldas);
					setText(celda, texto);
				}
				columna = 0;
				fila++;
			}
			
			//Mensaje
			fila = fila + 2;
			columna = columnas - 2;
			celda = getCell(planillaElectronica, fila, columna);
			setText(celda, mensaje);
			
			//Combinamos las celdas correspondientes al logo de la aplicación
			planillaElectronica.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));
			
			//Combinamos las celdas correspondientes al logo de la empresa
			planillaElectronica.addMergedRegion(new CellRangeAddress(1, 1, columnas - 1, columnas));
			
			//Combinamos las celdas correspondientes al título del reporte
			planillaElectronica.addMergedRegion(new CellRangeAddress(2, 2, 1, columnas - 3));
			
			//Combinamos las celdas correspondientes a la fecha del reporte
			planillaElectronica.addMergedRegion(new CellRangeAddress(2, 2, columnas - 2, columnas));
			
			//Combinamos las celdas correspondientes al mensaje
			planillaElectronica.addMergedRegion(new CellRangeAddress(fila, fila, columna, columna + 2));
			
			columna = 1;
			for(; columna < columnas + 1; columna++){
				planillaElectronica.autoSizeColumn(columna);
			}
			
			//Ajustamos las imágenes
			if(imagenLogoAplicacion != null) {
				imagenLogoAplicacion.resize();
			}
			if(imagenLogoEmpresa != null) {
				imagenLogoEmpresa.resize();
			}
			
			//Generamos el nombre del archivo
			String archivo = UUID.randomUUID().toString() + ".xls";
			response.setHeader("Content-Disposition", "attachment; filename=" + archivo);
			response.setHeader("Pragma", "no-cache");
		    response.setHeader("Cache-Control", "no-cache");
			response.setContentType("application/vnd.ms-excel");
		} catch (Throwable t) {
			log.error(t);
		}
	}
}
